package com.onec.service.manage.aspect;

import com.onec.service.api.annotation.RedisLock;
import com.onec.service.api.dto.response.BaseResponse;
import com.onec.service.api.enums.ResultCodeEnum;
import com.onec.service.manage.config.RedisLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.UUID;

/**
 * redis spring 分布式锁
 *
 * @author ONEC
 */
@Configuration
@Aspect
@Slf4j
public class RedisLockAspect {

    @Resource
    RedisLockUtil redisLockUtil;

    @Pointcut("@annotation(com.onec.service.api.annotation.RedisLock)")
    public void redisLock() {
    }


    /**
     * 增强环绕通知
     *
     * @param joinPoint
     */
    @Around(value = "redisLock()")
    public Object responseAround(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        RedisLock redisLock = method.getAnnotation(RedisLock.class);
        String key = redisLock.prefix();
        String value = UUID.randomUUID().toString();
        boolean isLock = redisLockUtil.getLock(key, value, redisLock.expire(), redisLock.unit());
        if (isLock) {
            Object result = null;
            try {
                result = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            } finally {
                redisLockUtil.releaseLock(key, value);
            }
            return  result;
        }
        return BaseResponse.error(ResultCodeEnum.CLIENT_REDIS_LOCK_FAILED);
    }
}
